package com.game.jumpdino.logic;

import java.util.ArrayList;
import java.util.List;

import com.game.jumpdino.R;
import com.game.jumpdino.logic.visual.Avatar;
import com.game.jumpdino.logic.visual.Blocker;
import com.game.jumpdino.logic.visual.BreakBamboo;
import com.game.jumpdino.logic.visual.Holder;
import com.game.jumpdino.logic.visual.Kite;
import com.game.jumpdino.logic.visual.Umbrella;
import com.game.jumpdino.logic.visual.VisualBase;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.media.MediaPlayer;

/**
 * @author guhu
 * 
 */
public class Playground {
	private Drawable mBackground;
	private PlaygroundVisualFactory visualFactory = new PlaygroundVisualFactory();
	private Holder mostTopHolder;
	private Blocker mostTopBlocker;
	private GameState state;
	private int lifes;
	public static int score = 0;
	private static int width;
	private static int height;
	private static int avatarMinHeight;
	private static Playground current;

	public List<Blocker> blockers;
	public List<Holder> holders;
	public Avatar avatar;
	public int movingDirection = 0;
	private int reverseOperation = 1;
	public boolean isLeftPressed;
	public boolean isRightPressed;
	public Context mContext;

	public Playground(Context context) {
		Playground.current = this;
		blockers = new ArrayList<Blocker>();
		holders = new ArrayList<Holder>();
		state = GameState.Ready;
		mContext = context;
		mBackground = context.getResources().getDrawable(R.drawable.back);
	}
	
	public static Playground getCurrent(){
		return current;
	}
	
	public int getReverseOperation() {
		return reverseOperation;
	}

	public void setReverseOperation(int reverseOperation) {
		this.reverseOperation = reverseOperation;
	}

	public Holder getMostTopHolder() {
		return mostTopHolder;
	}

	public void setMostTopHolder(Holder holder) {
		mostTopHolder = holder;
	}

	public Blocker getMostTopBlocker() {
		return mostTopBlocker;
	}

	public void setMostTopBlocker(Blocker blocker) {
		mostTopBlocker = blocker;
	}

	public Context getContext() {
		return mContext;
	}

	public void initialPlaygroundSize(int w, int h) {
		width = w;
		height = h;
		avatarMinHeight = 4 * h / 12;
		mBackground.setBounds(0, 0, w, h);
	}

	public static int getWidth() {
		return width;
	}

	public static int getHeight() {
		return height;
	}

	public void setState(GameState s) {
		state = s;
	}

	public GameState getState() {
		return state;
	}
	
	public int getLifeCount(){
		return lifes;
	}
	
	public void addHolder(Holder holder){
		holders.add(holder);
	}
	
	public void newMatch(){
		holders.clear();
		blockers.clear();
		this.mostTopBlocker = null;
		this.mostTopHolder = null;
		movingDirection = 0;
		reverseOperation = 1;
		generateVisuals();		
		for (VisualConfig config : GameConfiguration.getCurrent()) {
			if (config != null){
				config.Reset();
			}
		}
		VisualBase.setMinSpeedUp(VisualBase.defaultJumpSpeed);
		avatar = (Avatar) GameConfiguration.generateVisual(VisualConfig.getAvatarConfig(), mContext);
		avatar.move(width / 2, height / 3);
		state = GameState.Started;
	}

	public void Reset() {
		lifes = 2;
		newMatch();
	}

	public void drawOn(Canvas c) {
		if (c != null){
			mBackground.draw(c);
			for (VisualBase holder : holders) {
				holder.drawOn(c);
			}
			for (VisualBase blocker : blockers) {
				blocker.drawOn(c);
			}
			if (avatar != null) {
				avatar.drawOn(c);
				if (avatar.getAttachTo() != null){
					avatar.getAttachTo().drawOn(c);
				}
			}
		}
	}

	public void doMove() {		
		VisualBase moveTarget = avatar;
		if (avatar.getAttachTo() != null){
			moveTarget = avatar.getAttachTo();
		}

		if (movingDirection == 0) { 
			// Visual Base already do it.
//			if (moveTarget.getVelocity().x > 0) {
//			    moveTarget.setVx(moveTarget.getVelocity().x - Avatar.defaultGX);
//			    if (moveTarget.getVelocity().x < 0){
//			    	moveTarget.setVx(0.0f); 
//			    }
//			} else if (moveTarget.getVelocity().x < 0) {
//				moveTarget.setVx(moveTarget.getVelocity().x + Avatar.defaultGX);
//			    if (moveTarget.getVelocity().x > 0){
//			    	moveTarget.setVx(0.0f);
//			    }
//			}
		} else if (moveTarget.getVelocity().x == 0 && movingDirection != 0){
			moveTarget.setVx(movingDirection * 8);
		} else if (moveTarget.getVelocity().x * movingDirection < 0){
			moveTarget.setVx(movingDirection * 8);
		} else if (moveTarget.getVelocity().x * movingDirection > 0){
			// Keep the speed
			moveTarget.setVx(moveTarget.getVelocity().x + movingDirection * Avatar.defaultGX);
		}
		
		for (VisualBase holder : holders) {
			holder.doMove();
		}

		for (VisualBase blocker : blockers) {
			blocker.doMove();
		}

		// Only avatar move.
		if (avatar.getPosition().top >= avatarMinHeight
				|| avatar.getVelocity().y > 0) {
			if (avatar.getPosition().bottom < height || avatar.getAttachTo() != null){
				avatar.doMove();
			} else {
				avatar.setVy(avatar.getVelocity().y + 5);
			}
		} else { // Move holders and blockers.
			float move = -avatar.getVelocity().y;
			if (avatar.getAttachTo() != null){
				move = -avatar.getAttachTo().getVelocity().y;
			}
			score += move;
			for (VisualBase holder : holders) {
				holder.move(0, move);
			}

			for (VisualBase blocker : blockers) {
				blocker.move(0, move);
			}
			
			// The following operation will not effect when avatar attached.
			avatar.updateVelocity(0, avatar.getG());
			avatar.move(avatar.getVelocity().x, 0);
		}
		
    	// After move, hit test for blockers and holders.
		if (avatar.getAttachTo() == null){ 
			for (VisualBase blocker : blockers) {
				if (blocker.hitTop(avatar)) {
					blocker.onHit(avatar, this);
					avatar.onHit(blocker, this);
					break;
				}
			}
			
			for (VisualBase holder : holders) {
				if (holder.hitBottom(avatar)) {
					holder.onHit(avatar, this);
					avatar.onHit(holder, this);
					break;
				}
			}
		}
		// When avatar is failling down. Move all others up
		if (avatar.getAttachTo() == null && avatar.getPosition().bottom >= height){
			float move = -avatar.getVelocity().y;
			int holderCount = 0;
			for (VisualBase holder : holders) {
				holder.move(0, move);
				// Don't wait for a failing bamboo or umbrella or kite.
				if (!(holder instanceof BreakBamboo ||
					  holder instanceof Umbrella ||
					  holder instanceof Kite)){
					++holderCount;
				}
			}

			for (VisualBase blocker : blockers) {
				blocker.move(0, move);
			}
			
			if (holderCount <= 0 && blockers.size() <= 0) {
				holders.clear();
				Fail();
				return;
			}
			cleanVisuals();
		} else {
			cleanVisuals();
			generateVisuals();			
		}
	}
	
	public void Fail(){
		if (lifes <= 0){
			state = GameState.Stoped;
		} else {
			--lifes;
			state = GameState.NewLife;
		}
		MediaPlayer player = MediaPlayer.create(mContext, R.raw.fail);
		player.start();
	}

	private void cleanVisuals() {
		for (int i = 0; i < holders.size(); i++) {
			VisualBase holder = holders.get(i);
			if (holder == null){
				holders.remove(i--);
				continue;
			}
			if (holder.getPosition().top >= height
					|| holder.getPosition().bottom <= 0
					|| holder.isValid() == false) {
				if (holder.getFollows().isEmpty()){
					holder.getProperties().showedCount--;
					if (holder.getProperties().mVisualEventListener != null){
						holder.getProperties().mVisualEventListener.onRemoved(holder);
					}
					holders.remove(i);
					i--;
				}
			}
		}

		for (int i = 0; i < blockers.size(); i++) {
			VisualBase blocker = blockers.get(i);
			if (blocker.getPosition().top >= height
					|| blocker.getPosition().bottom <= 0
					|| blocker.isValid() == false) {
				blocker.getProperties().showedCount--;
				if (blocker.getProperties().mVisualEventListener != null){
					blocker.getProperties().mVisualEventListener.onRemoved(blocker);
				}
				blockers.remove(i);
				i--;
			}
		}
	}

	private void generateVisuals() {
		visualFactory.fillInVisuals(this);
	}
}